home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_include / ASM-I386 / BUGS.H < prev    next >
C/C++ Source or Header  |  1999-09-17  |  10KB  |  376 lines

  1. /*
  2.  *  include/asm-i386/bugs.h
  3.  *
  4.  *  Copyright (C) 1994  Linus Torvalds
  5.  *
  6.  *  Cyrix stuff, June 1998 by:
  7.  *    - Rafael R. Reilova (moved everything from head.S),
  8.  *        <rreilova@ececs.uc.edu>
  9.  *    - Channing Corn (tests & fixes),
  10.  *    - Andrew D. Balsa (code cleanup).
  11.  */
  12.  
  13. /*
  14.  * This is included by init/main.c to check for architecture-dependent bugs.
  15.  *
  16.  * Needs:
  17.  *    void check_bugs(void);
  18.  */
  19.  
  20. #include <linux/config.h>
  21. #include <asm/processor.h>
  22.  
  23. #define CONFIG_BUGi386
  24.  
  25. __initfunc(static void no_halt(char *s, int *ints))
  26. {
  27.     boot_cpu_data.hlt_works_ok = 0;
  28. }
  29.  
  30. __initfunc(static void no_387(char *s, int *ints))
  31. {
  32.     boot_cpu_data.hard_math = 0;
  33.     write_cr0(0xE | read_cr0());
  34. }
  35.  
  36. static char __initdata fpu_error = 0;
  37.  
  38. __initfunc(static void copro_timeout(void))
  39. {
  40.     fpu_error = 1;
  41.     timer_table[COPRO_TIMER].expires = jiffies+100;
  42.     timer_active |= 1<<COPRO_TIMER;
  43.     printk(KERN_ERR "387 failed: trying to reset\n");
  44.     send_sig(SIGFPE, current, 1);
  45.     outb_p(0,0xf1);
  46.     outb_p(0,0xf0);
  47. }
  48.  
  49. static double __initdata x = 4195835.0;
  50. static double __initdata y = 3145727.0;
  51.  
  52. __initfunc(static void check_fpu(void))
  53. {
  54.     unsigned short control_word;
  55.  
  56.     if (!boot_cpu_data.hard_math) {
  57. #ifndef CONFIG_MATH_EMULATION
  58.         printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
  59.         printk(KERN_EMERG "Giving up.\n");
  60.         for (;;) ;
  61. #endif
  62.         return;
  63.     }
  64.     /*
  65.      * check if exception 16 works correctly.. This is truly evil
  66.      * code: it disables the high 8 interrupts to make sure that
  67.      * the irq13 doesn't happen. But as this will lead to a lockup
  68.      * if no exception16 arrives, it depends on the fact that the
  69.      * high 8 interrupts will be re-enabled by the next timer tick.
  70.      * So the irq13 will happen eventually, but the exception 16
  71.      * should get there first..
  72.      */
  73.     printk(KERN_INFO "Checking 386/387 coupling... ");
  74.     timer_table[COPRO_TIMER].expires = jiffies+50;
  75.     timer_table[COPRO_TIMER].fn = copro_timeout;
  76.     timer_active |= 1<<COPRO_TIMER;
  77.     __asm__("clts ; fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
  78.     control_word &= 0xffc0;
  79.     __asm__("fldcw %0 ; fwait": :"m" (*&control_word));
  80.     outb_p(inb_p(0x21) | (1 << 2), 0x21);
  81.     __asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
  82.     timer_active &= ~(1<<COPRO_TIMER);
  83.     if (fpu_error)
  84.         return;
  85.     if (!ignore_irq13) {
  86.         printk("OK, FPU using old IRQ 13 error reporting\n");
  87.         return;
  88.     }
  89.     __asm__("fninit\n\t"
  90.         "fldl %1\n\t"
  91.         "fdivl %2\n\t"
  92.         "fmull %2\n\t"
  93.         "fldl %1\n\t"
  94.         "fsubp %%st,%%st(1)\n\t"
  95.         "fistpl %0\n\t"
  96.         "fwait\n\t"
  97.         "fninit"
  98.         : "=m" (*&boot_cpu_data.fdiv_bug)
  99.         : "m" (*&x), "m" (*&y));
  100.     if (!boot_cpu_data.fdiv_bug)
  101.         printk("OK, FPU using exception 16 error reporting.\n");
  102.     else
  103.         printk("Hmm, FPU using exception 16 error reporting with FDIV bug.\n");
  104. }
  105.  
  106. __initfunc(static void check_hlt(void))
  107. {
  108.     printk(KERN_INFO "Checking 'hlt' instruction... ");
  109.     if (!boot_cpu_data.hlt_works_ok) {
  110.         printk("disabled\n");
  111.         return;
  112.     }
  113.     __asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
  114.     printk("OK.\n");
  115. }
  116.  
  117. /*
  118.  *    Most 386 processors have a bug where a POPAD can lock the 
  119.  *    machine even from user space.
  120.  */
  121.  
  122. __initfunc(static void check_popad(void))
  123. {
  124. #ifndef CONFIG_X86_POPAD_OK
  125.     int res, inp = (int) &res;
  126.  
  127.     printk(KERN_INFO "Checking for popad bug... ");
  128.     __asm__ __volatile__( 
  129.       "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
  130.       : "=&a" (res)
  131.       : "d" (inp)
  132.       : "ecx", "edi" );
  133.     /* If this fails, it means that any user program may lock the CPU hard. Too bad. */
  134.     if (res != 12345678) printk( "Buggy.\n" );
  135.                 else printk( "OK.\n" );
  136. #endif
  137. }
  138.  
  139. /*
  140.  *    B step AMD K6 before B 9730xxxx have hardware bugs that can cause
  141.  *    misexecution of code under Linux. Owners of such processors should
  142.  *    contact AMD for precise details and a CPU swap.
  143.  *
  144.  *    See    http://www.mygale.com/~poulot/k6bug.html
  145.  *        http://www.amd.com/K6/k6docs/revgd.html
  146.  *
  147.  *    The following test is erm.. interesting. AMD neglected to up
  148.  *    the chip setting when fixing the bug but they also tweaked some
  149.  *    performance at the same time..
  150.  */
  151.  
  152. extern void vide(void);
  153. __asm__(".align 4\nvide: ret");
  154.  
  155. __initfunc(static void check_amd_k6(void))
  156. {
  157.     if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
  158.         boot_cpu_data.x86_model == 6 &&
  159.         boot_cpu_data.x86_mask == 1)
  160.     {
  161.         int n;
  162.         void (*f_vide)(void);
  163.         unsigned long d, d2;
  164.  
  165.         printk(KERN_INFO "AMD K6 stepping B detected - ");
  166.  
  167. #define K6_BUG_LOOP 1000000
  168.  
  169.         /*
  170.          * It looks like AMD fixed the 2.6.2 bug and improved indirect 
  171.          * calls at the same time.
  172.          */
  173.  
  174.         n = K6_BUG_LOOP;
  175.         f_vide = vide;
  176.         __asm__ ("rdtsc" : "=a" (d));
  177.         while (n--) 
  178.             f_vide();
  179.         __asm__ ("rdtsc" : "=a" (d2));
  180.         d = d2-d;
  181.  
  182.         /* Knock these two lines out if it debugs out ok */
  183.         printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
  184.         printk(KERN_INFO "AMD K6 stepping B detected - ");
  185.         /* -- cut here -- */
  186.         if (d > 20*K6_BUG_LOOP) 
  187.             printk("system stability may be impaired when more than 32 MB are used.\n");
  188.         else 
  189.             printk("probably OK (after B9730xxxx).\n");
  190.         printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
  191.     }
  192. }
  193.  
  194. /*
  195.  * All current models of Pentium and Pentium with MMX technology CPUs
  196.  * have the F0 0F bug, which lets nonpriviledged users lock up the system:
  197.  */
  198.  
  199. extern void trap_init_f00f_bug(void);
  200.  
  201. __initfunc(static void check_pentium_f00f(void))
  202. {
  203.     /*
  204.      * Pentium and Pentium MMX
  205.      */
  206.     boot_cpu_data.f00f_bug = 0;
  207.     if (boot_cpu_data.x86 == 5 && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
  208.         printk(KERN_INFO "Intel Pentium with F0 0F bug - workaround enabled.\n");
  209.         boot_cpu_data.f00f_bug = 1;
  210.         trap_init_f00f_bug();
  211.     }
  212. }
  213.  
  214. /*
  215.  * Perform the Cyrix 5/2 test. A Cyrix won't change
  216.  * the flags, while other 486 chips will.
  217.  */
  218.  
  219. static inline int test_cyrix_52div(void)
  220. {
  221.     unsigned int test;
  222.  
  223.     __asm__ __volatile__(
  224.          "sahf\n\t"        /* clear flags (%eax = 0x0005) */
  225.          "div %b2\n\t"    /* divide 5 by 2 */
  226.          "lahf"        /* store flags into %ah */
  227.          : "=a" (test)
  228.          : "0" (5), "q" (2)
  229.          : "cc");
  230.  
  231.     /* AH is 0x02 on Cyrix after the divide.. */
  232.     return (unsigned char) (test >> 8) == 0x02;
  233. }
  234.  
  235. /*
  236.  * Fix cpuid problems with Cyrix CPU's:
  237.  *   -- on the Cx686(L) the cpuid is disabled on power up.
  238.  *   -- braindamaged BIOS disable cpuid on the Cx686MX.
  239.  */
  240.  
  241. extern unsigned char Cx86_dir0_msb;  /* exported HACK from cyrix_model() */
  242.  
  243. __initfunc(static void check_cx686_cpuid(void))
  244. {
  245.     if (boot_cpu_data.cpuid_level == -1 &&
  246.         ((Cx86_dir0_msb == 5) || (Cx86_dir0_msb == 3))) {
  247.         int eax, dummy;
  248.         unsigned char ccr3, ccr4;
  249.  
  250.         cli();
  251.         ccr3 = getCx86(CX86_CCR3);
  252.         setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
  253.         ccr4 = getCx86(CX86_CCR4);
  254.         setCx86(CX86_CCR4, ccr4 | 0x80);          /* enable cpuid  */
  255.         setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
  256.         sti();
  257.  
  258.         /* we have up to level 1 available on the Cx6x86(L|MX) */
  259.         boot_cpu_data.cpuid_level = 1;
  260.         cpuid(1, &eax, &dummy, &dummy,
  261.               &boot_cpu_data.x86_capability);
  262.  
  263.         boot_cpu_data.x86 = (eax >> 8) & 15;
  264.         /*
  265.           * we already have a cooked step/rev number from DIR1
  266.          * so we don't use the cpuid-provided ones.
  267.          */
  268.     }
  269. }
  270.  
  271. /*
  272.  * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
  273.  * BIOSes for compatability with DOS games.  This makes the udelay loop
  274.  * work correctly, and improves performance.
  275.  */
  276.  
  277. extern void calibrate_delay(void) __init;
  278.  
  279. __initfunc(static void check_cx686_slop(void))
  280. {
  281.     if (Cx86_dir0_msb == 3) {
  282.         unsigned char ccr3, ccr5;
  283.  
  284.         cli();
  285.         ccr3 = getCx86(CX86_CCR3);
  286.         setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
  287.         ccr5 = getCx86(CX86_CCR5);
  288.         if (ccr5 & 2)
  289.             setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
  290.         setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
  291.         sti();
  292.  
  293.         if (ccr5 & 2) { /* possible wrong calibration done */
  294.             printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
  295.             calibrate_delay();
  296.             boot_cpu_data.loops_per_sec = loops_per_sec;
  297.         }
  298.     }
  299. }
  300.  
  301. /*
  302.  * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
  303.  * by the fact that they preserve the flags across the division of 5/2.
  304.  * PII and PPro exhibit this behavior too, but they have cpuid available.
  305.  */
  306.  
  307. __initfunc(static void check_cyrix_cpu(void))
  308. {
  309.     if ((boot_cpu_data.cpuid_level == -1) && (boot_cpu_data.x86 == 4)
  310.         && test_cyrix_52div()) {
  311.  
  312.         strcpy(boot_cpu_data.x86_vendor_id, "CyrixInstead");
  313.     }
  314. }
  315.  
  316. /*
  317.  * Check wether we are able to run this kernel safely on SMP.
  318.  *
  319.  * - In order to run on a i386, we need to be compiled for i386
  320.  *   (for due to lack of "invlpg" and working WP on a i386)
  321.  * - In order to run on anything without a TSC, we need to be
  322.  *   compiled for a i486.
  323.  * - In order to work on a Pentium/SMP machine, we need to be
  324.  *   compiled for a Pentium or lower, as a PPro config implies
  325.  *   a properly working local APIC without the need to do extra
  326.  *   reads from the APIC.
  327. */
  328.  
  329. __initfunc(static void check_config(void))
  330. {
  331. /*
  332.  * We'd better not be a i386 if we're configured to use some
  333.  * i486+ only features! (WP works in supervisor mode and the
  334.  * new "invlpg" and "bswap" instructions)
  335.  */
  336. #if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_BSWAP)
  337.     if (boot_cpu_data.x86 == 3)
  338.         panic("Kernel requires i486+ for 'invlpg' and other features");
  339. #endif
  340.  
  341. /*
  342.  * If we configured ourselves for a TSC, we'd better have one!
  343.  */
  344. #ifdef CONFIG_X86_TSC
  345.     if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC))
  346.         panic("Kernel compiled for Pentium+, requires TSC");
  347. #endif
  348.  
  349. /*
  350.  * If we were told we had a good APIC for SMP, we'd better be a PPro
  351.  */
  352. #if defined(CONFIG_X86_GOOD_APIC) && defined(CONFIG_SMP)
  353.     if (smp_found_config && boot_cpu_data.x86 <= 5)
  354.         panic("Kernel compiled for PPro+, assumes local APIC without read-before-write bug");
  355. #endif
  356. }
  357.  
  358. __initfunc(static void check_bugs(void))
  359. {
  360.     check_cyrix_cpu();
  361.     identify_cpu(&boot_cpu_data);
  362.     check_cx686_cpuid();
  363.     check_cx686_slop();
  364. #ifndef __SMP__
  365.     printk("CPU: ");
  366.     print_cpu_info(&boot_cpu_data);
  367. #endif
  368.     check_config();
  369.     check_fpu();
  370.     check_hlt();
  371.     check_popad();
  372.     check_amd_k6();
  373.     check_pentium_f00f();
  374.     system_utsname.machine[1] = '0' + boot_cpu_data.x86;
  375. }
  376.